#include <Arduino.h>
#include <stdio.h>
#include <stdlib.h>
#include <ModbusMaster.h>
//#include <Arduino_FreeRTOS.h>
//#include <semphr.h>
#include <ModbusRTUSlave.h>
#include<string.h>


#include <WiFi.h>
#include "WiFiClient.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
 
#define WLAN_SSID "xiaomi"  //wifi名称
#define WLAN_PASS "88888888"  //wifi密码
 
 
#define MQTT_SERVER     "broker.emqx.io" //服务器地址，这里使用的是公网所以下面的用户和密码可以随便
 
#define MQTT_SERVERPORT 1883
#define MQTT_USERNAME    "d1"//用户名称和密码，用的公网可以不填可随机
#define MQTT_KEY         "d1"


const char *pin = "1234"; // Change this to more secure PIN.

#define testserial Serial2

xSemaphoreHandle xMutex;//互斥量



ModbusRTUSlave modbus(Serial2);
ModbusMaster node;//从站1
ModbusMaster node1;//从站2

volatile uint16_t value_CO2;
volatile uint16_t value_O2;

volatile uint16_t value_Concentration_1;//浓度
volatile uint16_t value_Concentration_2;
volatile uint8_t Concentration_1;
volatile uint8_t Concentration_2;
volatile uint8_t Concentration_3;
volatile uint8_t Concentration_4;

volatile uint16_t value_Absorbance_1;//吸光度
volatile uint16_t value_Absorbance_2;
volatile uint8_t Absorbance_1;
volatile uint8_t Absorbance_2;
volatile uint8_t Absorbance_3;
volatile uint8_t Absorbance_4;

//volatile uint16_t value_Temperature_1;//温度
//volatile uint16_t value_Temperature_2;
//volatile uint8_t Temperature_1;
//volatile uint8_t Temperature_2;
//volatile uint8_t Temperature_3;
//volatile uint8_t Temperature_4;

//volatile uint16_t value_VoltageA_1;//电压A
//volatile uint16_t value_VoltageA_2;
//volatile uint8_t VoltageA_1;
//volatile uint8_t VoltageA_2;
//volatile uint8_t VoltageA_3;
//volatile uint8_t VoltageA_4;

//volatile uint16_t value_VoltageB_1;//电压B
//volatile uint16_t value_VoltageB_2;
//volatile uint8_t VoltageB_1;
//volatile uint8_t VoltageB_2;
//volatile uint8_t VoltageB_3;
//volatile uint8_t VoltageB_4;

//volatile uint8_t CO2_1;
//volatile uint8_t CO2_2;
//volatile uint8_t O2_1;
//volatile uint8_t O2_2;

bool coils[2];
bool discreteInputs[2];
uint16_t holdingRegisters[2];
uint16_t inputRegisters[2];

//unsigned int iqw=0x2C59DE40;
//unsigned int hex=0x41360000;

int state=1;
int DA;

//char item[8] = {0x01,0x03,0x00,0x00,0x00,0x02,0xC4,0x0B};//发送modbus请求信息
//char item1[8] = {0x02,0x03,0x00,0x00,0x00,0x02,0xC4,0x0B};//发送modbus请求信息

uint8_t result;

WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, MQTT_SERVERPORT, MQTT_USERNAME, MQTT_KEY);
Adafruit_MQTT_Publish pub = Adafruit_MQTT_Publish(&mqtt,"my/mqtt/topic"); // 发布主题


void task_senddata(void);
void task_modbusdata(void *pvParameters);//对从机1（co2传感器）发送modbus请求信息;
void end();
void MQTT_connect();
void MQTT_send();
void task_LCDrec();

void setup(){

  Serial.begin(9600);
  Serial1.begin(9600,SERIAL_8N1,18,19);
  testserial.begin(9600);

  node.begin(50, Serial2);//从机1节点开启
  node1.begin(2, Serial2);//从机2点开启

  holdingRegisters[0]=8888;
  holdingRegisters[1]=7777;
  holdingRegisters[2]=state;
  
  modbus.configureCoils(coils, 4);                       // bool array of coil values, number of coils
  modbus.configureDiscreteInputs(discreteInputs, 2);     // bool array of discrete input values, number of discrete inputs
  modbus.configureHoldingRegisters(holdingRegisters, 4); // unsigned 16 bit integer array of holding register values, number of holding registers
  modbus.configureInputRegisters(inputRegisters, 2);     // unsigned 16 bit integer array of input register values, number of input registers
  modbus.begin(1, 9600,SERIAL_8N1);//单片机作为从机时，从机ID为1，波特率9600，SERIAL_8N1表示无奇偶校验

  xMutex=xSemaphoreCreateMutex();//获取互斥量

  xTaskCreate(task_senddata, "task1_task",2024,NULL,1,NULL); //串口屏同步信息
  xTaskCreate(task_modbusdata, "task2_task",2024,NULL,1,NULL); //从机1任务
  //xTaskCreate(task_modbusdata1, "task3_task",2024,NULL,1,NULL); //从机2任务
  xTaskCreate(task_LCDrec, "task6_task",2024,NULL,1,NULL); //触摸屏任务
  //xTaskCreate(task_modbusslave, "task4_task",2024,NULL,2,NULL); //接收主机任务
  xTaskCreate(MQTT_send, "task5_task",2024,NULL,2,NULL); //MQTT任务

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  delay(2000);
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);
  while(WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  
}

void loop() {
    //float fdata=0;
    //char text[2]={O2_2,O2_1};
    //memcpy(&fdata,text,sizeof(fdata));
    //Serial.println(fdata);
    //xSemaphoreGive(xMutex);
    //double* fp=(double*)&hex;
    //Serial.println(*fp,6);
  //if (Serial.available()) {        // If anything comes in Serial (USB),
  //  testserial.write(Serial.read());  // read it and send it out Serial1 (pins 0 & 1)
  //}
  //if (Serial1.available()) {        // If anything comes in Serial (USB),
  //  Serial.write(Serial.read());  // read it and send it out Serial1 (pins 0 & 1)
  //}
  //if (testserial.available()) {       // If anything comes in Serial1 (pins 0 & 1)
  //  Serial.write(testserial.read());  // read it and send it out Serial (USB)
  //}
}

void task_modbusdata(void *pvParameters)//对从机1（co2传感器）发送modbus请求信息
{
  while(1)
  {
  //if(xSemaphoreTake(xMutex,portMAX_DELAY))
  //{
  xSemaphoreTake(xMutex,portMAX_DELAY);//获取互斥量
  result = node.readHoldingRegisters(0x0156,2);//发送读功能码
  //result = node.readInputRegisters(0x00,2);//发送读功能码
  if (result == node.ku8MBSuccess) 
  {
    value_Concentration_1=node.getResponseBuffer(0);//获取浓度
    value_Concentration_2=node.getResponseBuffer(1);

    Concentration_1=(value_Concentration_1&0xff00)>>8;//转换为16进制
    Concentration_2=(value_Concentration_1&0x00ff);
    Concentration_3=(value_Concentration_2&0xff00)>>8;
    Concentration_4=(value_Concentration_2&0x00ff);
    xSemaphoreGive(xMutex);//释放互斥量
    vTaskDelay(pdMS_TO_TICKS(1000));
  } 
  else 
  {
    // 打印错误信息
    Serial.print("Error: ");
    Serial.println(result);
    xSemaphoreGive(xMutex);
    vTaskDelay(pdMS_TO_TICKS(1000));
    
  }
  }
}

void task_modbusdata1(void *pvParameters)//对从机2（o2传感器）发送modbus请求信息
{
   while(1)
  {
  //if(xSemaphoreTake(xMutex,portMAX_DELAY))
  //{ 
  xSemaphoreTake(xMutex,portMAX_DELAY);//获取互斥量
  result = node.readHoldingRegisters(0x015A,2);//发送读功能码
  //result = node.readHoldingRegisters(0x0127,1);//发送读功能码
  if (result == node.ku8MBSuccess) 
  {
    value_Absorbance_1=node.getResponseBuffer(0);//获取吸光度
    value_Absorbance_2=node.getResponseBuffer(1);

    Absorbance_1=(value_Absorbance_1&0xff00)>>8;
    Absorbance_2=(value_Absorbance_1&0x00ff);
    Absorbance_3=(value_Absorbance_2&0xff00)>>8;
    Absorbance_4=(value_Absorbance_2&0x00ff);

    xSemaphoreGive(xMutex);//释放互斥量
    vTaskDelay(pdMS_TO_TICKS(1000));
  } 
  else 
  {
    // 打印错误信息
    Serial.print("Error: ");
    Serial.println(result);
    xSemaphoreGive(xMutex);
    vTaskDelay(pdMS_TO_TICKS(1000));
    
  }
  }
}

void task_senddata(void *pvParameters)//发送显示屏信息的任务
{
  while(1)
  {
   //if (testserial.available()){
    //Serial1.write(testserial.read())
    
  //}
  char Concentration[4]={Concentration_2,Concentration_1,Concentration_4,Concentration_3};
  char Absorbance[4]={Absorbance_2,Absorbance_1,Absorbance_4,Absorbance_3};
  //char Absorbance[2]={Absorbance_1,Absorbance_2};
  //char Temperature[4]={Temperature_4,Temperature_3,Temperature_2,Temperature_1};
  //char VoltageA[4]={VoltageA_4,VoltageA_3,VoltageA_2,VoltageA_1};
  //char VoltageB[4]={VoltageB_4,VoltageB_3,VoltageB_2,VoltageB_1};
  float fdata1=0,fdata2=0,fdata3=0,fdata4=0,fdata5=0;
  memcpy(&fdata1,Concentration,sizeof(fdata1));
  memcpy(&fdata2,Absorbance,sizeof(fdata2));
  //memcpy(&fdata3,Temperature,sizeof(fdata3));
  //memcpy(&fdata4,VoltageA,sizeof(fdata4));
  //memcpy(&fdata5,VoltageB,sizeof(fdata5));
  Serial.println(fdata1,6);Serial.println(fdata2,6);
  //Serial.println(wee);
  //char data[8] = {0x01,0x03,Concentration_2,Concentration_1,Concentration_4,Concentration_3}; //把从传感器获得的数据包装起来
  //for (int i = 0 ; i < 6; i++) {  
  // Serial1.write(data[i]);   // 输出到串口屏
   //Serial.println(data[i]);   // 输出到串口屏
  //}
  //Serial1.print("t3.txt=\"66\"\xff\xff\xff");
  char str[100];
  int data=fdata1*5000;
  DA=data;

  sprintf(str,"n0.val=%d",data);
  Serial1.print(str);
  end();
  delay(1000);
  }
}

void task_LCDrec(void *pvParameters)
{
  while(1)
  {
  if(Serial1.available()>1)
  {
    uint8_t cmd=0;
    cmd=Serial1.read();
    char dataA[8] = {0x32,0x06,0x01,0x51,0x00,0x01,0x0C,0x4E}; //传感器零点校准命令
    //switch(cmd)
    //{
    //    case 0xA1:
            
    //        for (int i = 0 ; i < 6; i++) { 
    //         Serial2.write(dataA[i]);   // 输出到传感器
    //        }
    //        Serial.println("Zero point calibration ON!");
    //        break;
    //    default:
    //        Serial.println("输入命令错误");
    //        break;
    //for (int i = 0 ; i < 6; i++) { 
    //         Serial2.write(dataA[i]);   // 输出到传感器
    //        }
    //        Serial.println("Zero point calibration ON!");
    if(cmd==0xA1)
    {
      for (int i = 0 ; i < 6; i++) { 
             Serial2.write(dataA[i]);   // 输出到传感器
            }
            Serial.println("Zero point calibration ON!");
    }
  }
  //cmd=0;
  //delay(10000);
  }
}

void task_modbusslave(void *pvParameters)//单片机作为modbus从机的任务，接收电脑的modbus请求
{
  while(1)
  {
  modbus.poll();//查看是否有modbus请求发送，如收到请求，则返回相应的响应码
  holdingRegisters[0]=value_CO2;
  holdingRegisters[1]=value_O2;
  if(holdingRegisters[3]==1)//主机修改寄存器值为1时，进入零点校准
  {
    Serial.println("当前执行：零点校准");
    state=2;
    holdingRegisters[2]=state;
  }
  if(holdingRegisters[3]==2)//主机修改寄存器值为2时，进入量程校准
  {
    Serial.println("当前执行：量程校准");
    state=2;
    holdingRegisters[2]=state;
  }
  delay(1000);
  }
}

void end()
{
  Serial1.write(0xff);
  Serial1.write(0xff);
  Serial1.write(0xff);

}

void MQTT_connect()//连接mqtt服务器，5s连接一次
{
  int8_t ret;
  if(mqtt.connected())
  {
    return;
  }
  Serial.print("Connecting to MQTT... ");
  uint8_t retries = 5;//尝试5次
  while((ret = mqtt.connect()) != 0)
  {
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);
    retries--;
    if(retries == 0)//如果五次都没连接上进入死循环
    {
      while(1);
    }
    Serial.println("MQTT Connected!");
  }
}

void MQTT_send(void *pvParameters)
{
  while(1)
  {
  MQTT_connect();
  Serial.print(F("\nSending val "));
  //if(!pub.publish("{\"msg\":\"smoke\",\"value\":%d}"))//发布消息
  pub.publish("{\"msg\":\"smoke\",\"value\"}");
  if(!pub.publish(DA))
  //if(!pub.publish("{\"msg\":\"smoke\",\"value\":%d}"))
  {
    Serial.println(F("Failed"));
  }else
  {
    Serial.println(F("OK"));
  }
  delay(2000);
  }
}

